package com.smmisia.article.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smmisia.article.api.AuthService;
import com.smmisia.article.dto.accompany.AccompanyCreateDTO;
import com.smmisia.article.dto.accompany.AccompanyUpdateDTO;
import com.smmisia.article.dto.user.UserDTO;
import com.smmisia.article.entity.Accompany;
import com.smmisia.article.entity.AccompanyMember;
import com.smmisia.article.entity.convetor.AccompanyConvertor;
import com.smmisia.article.mapper.AccompanyMapper;
import com.smmisia.article.response.accompany.AccompanyAuditResponse;
import com.smmisia.article.response.accompany.AccompanyResponse;
import com.smmisia.article.service.AccompanyMemberService;
import com.smmisia.article.service.AccompanyService;
import com.smmisia.common.Result.Result;
import com.smmisia.article.entity.User;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author smmis
 * @description 针对表【accompany(结伴活动表)】的数据库操作Service实现
 * @createDate 2024-12-28 14:11:10
 */
@Service
public class AccompanyServiceImpl extends ServiceImpl<AccompanyMapper, Accompany>
        implements AccompanyService {

    @Autowired
    private AccompanyMemberService memberService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private AuthService authService;

    @Autowired
    private AccompanyMemberService accompanyMemberService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result createAccompany(AccompanyCreateDTO dto) {
        // 转换并保存结伴信息
        Accompany accompany = AccompanyConvertor.INSTANCE.toAccompanyEntity(dto);
        accompany.setCreatorId(StpUtil.getLoginIdAsLong());
        accompany.setCurrentMembers(1);
        accompany.setStatus(0);
        save(accompany);

        // 创建者加入结伴
        AccompanyMember member = new AccompanyMember();
        member.setAccompanyId(accompany.getId());
        member.setUserId(StpUtil.getLoginIdAsLong());
        member.setStatus(1);
        memberService.save(member);

        return Result.ok("创建结伴成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result joinAccompany(Long accompanyId) {
        String lockKey = "accompany:join:" + accompanyId;
        RLock lock = redissonClient.getLock(lockKey);

        try {
            if (!lock.tryLock(1, 5, TimeUnit.SECONDS)) {
                throw new RuntimeException("系统繁忙，请稍后重试");
            }

            // 检查结伴是否存在且在招募中
            Accompany accompany = getById(accompanyId);
            if (accompany == null || !Objects.equals(accompany.getStatus(), 0)) {
                throw new RuntimeException("该结伴不存在或已停止招募");
            }
            if(accompany.getCreatorId().equals(StpUtil.getLoginIdAsInt())){
                throw new RuntimeException("不能加入自己的结伴");
            }
            // 检查是否已达到人数上限
            if (accompany.getCurrentMembers() >= accompany.getMaxMembers()) {
                throw new RuntimeException("该结伴已达到人数上限");
            }

            // 创建申请记录
            Long userId = StpUtil.getLoginIdAsLong();
            AccompanyMember member = new AccompanyMember();
            member.setAccompanyId(accompanyId);
            member.setUserId(userId);
            member.setStatus(0); // 待审核状态
            memberService.save(member);

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("系统错误");
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return Result.ok("申请成功，请等管理员审核");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result auditAccompanyApply(Long memberId, Boolean approved) {
        AccompanyMember member = memberService.getById(memberId);
        if (member == null) {
            throw new RuntimeException("申请记录不存在");
        }

        if (approved) {
            // 使用分布式锁确保并发安全
            String lockKey = "accompany:audit:" + member.getAccompanyId();
            RLock lock = redissonClient.getLock(lockKey);

            try {
                if (!lock.tryLock(1, 5, TimeUnit.SECONDS)) {
                    throw new RuntimeException("系统繁忙，请稍后重试");
                }

                Accompany accompany = getById(member.getAccompanyId());
                if (accompany.getCurrentMembers() >= accompany.getMaxMembers()) {
                    throw new RuntimeException("该结伴已达到人数上限");
                }

                // 更新申请状态和加入时间
                member.setStatus(1);
                member.setJoinTime(LocalDateTime.now());
                memberService.updateById(member);

                // 更新当前人数
                accompany.setCurrentMembers(accompany.getCurrentMembers() + 1);
                if (accompany.getCurrentMembers().equals(accompany.getMaxMembers())) {
                    accompany.setStatus(1); // 设置为已满员
                }
                updateById(accompany);

            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("系统错误");
            } finally {
                if (lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        } else {
            // 拒绝申请
            member.setStatus(2);
            memberService.updateById(member);
        }
        return Result.ok("审核完成");
    }

    @Override
    public Result<Page<Accompany>> queryAccompanyPage(Integer page, Integer size) {
        return Result.ok(lambdaQuery()
                .eq(Accompany::getStatus, 0)
                .orderByDesc(Accompany::getCreatedTime)
                .page(new Page<>(page, size)));
    }

    @Override
    public Result<Page<Accompany>> queryMyJoinedAccompany(Integer page, Integer size) {
        // 获取当前用户ID
        Long userId = StpUtil.getLoginIdAsLong();

        // 查询用户参与的所有结伴ID
        List<Long> accompanyIds = memberService.lambdaQuery()
                .eq(AccompanyMember::getUserId, userId)
                .eq(AccompanyMember::getStatus, 1)  // 已通过的申请
                .list()
                .stream()
                .map(AccompanyMember::getAccompanyId)
                .collect(Collectors.toList());

        if (accompanyIds.isEmpty()) {
            return Result.ok(new Page<>(page, size));
        }

        // 查询结伴信息
        Page<Accompany> result = lambdaQuery()
                .in(Accompany::getId, accompanyIds)
                .orderByDesc(Accompany::getCreatedTime)
                .page(new Page<>(page, size));

        return Result.ok(result);
    }

    @Override
    public Result<Page<Accompany>> queryMyCreatedAccompany(Integer page, Integer size) {
        Long userId = StpUtil.getLoginIdAsLong();

        Page<Accompany> result = lambdaQuery()
                .eq(Accompany::getCreatorId, userId)
                .orderByDesc(Accompany::getCreatedTime)
                .page(new Page<>(page, size));

        return Result.ok(result);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result updateAccompany(Long id, AccompanyUpdateDTO dto) {
        // 检查结伴是否存在
        Accompany accompany = getById(id);
        if (accompany == null) {
            return Result.fail("结伴不存在");
        }

        // 检查是否是创建者
        Long userId = StpUtil.getLoginIdAsLong();
        if (!accompany.getCreatorId().equals(userId)) {
            return Result.fail("只有创建者可以修改结伴信息");
        }

        // 如果已经有人加入，不能修改最大人数
        if (accompany.getCurrentMembers() > 1 && !dto.getMaxMembers().equals(accompany.getMaxMembers())) {
            return Result.fail("已有成员加入，不能修改最大人数");
        }

        // 更新信息
        Accompany updateAccompany = AccompanyConvertor.INSTANCE.toAccompanyUpdateDTO(dto);
        updateAccompany.setId(id);
        updateById(updateAccompany);

        return Result.ok("更新成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result deleteAccompany(Long id) {
        // 检查结伴是否存在
        Accompany accompany = getById(id);
        if (accompany == null) {
            return Result.fail("结伴不存在");
        }

        // 检查是否是创建者
        Long userId = StpUtil.getLoginIdAsLong();
        if (!accompany.getCreatorId().equals(userId)) {
            return Result.fail("只有创建者可以删除结伴");
        }

        // 如果已经有人加入，不能删除
        if (accompany.getCurrentMembers() > 1) {
            return Result.fail("已有成员加入，不能删除");
        }

        // 删除结伴和相关成员记录
        removeById(id);
        memberService.lambdaUpdate()
                .eq(AccompanyMember::getAccompanyId, id)
                .remove();

        return Result.ok("删除成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<AccompanyResponse> getAccompanyById(Long id) {
        Accompany accompany = getById(id);
        if (accompany == null) {
            return Result.fail("结伴不存在");
        }
        AccompanyResponse response = AccompanyConvertor.INSTANCE.toAccompanyResponse(accompany);
        User user = authService.info(response.getCreatorId().intValue());
        response.setCreateUser(UserDTO.builder()
                .id(user.getId())
                .username(user.getUsername())
                .avatar(user.getAvatar())
                .uid(user.getUid())
                .email(user.getEmail())
                .build());
        List<UserDTO> list = new ArrayList<>();
        list.addAll(accompanyMemberService.lambdaQuery()
                .eq(AccompanyMember::getAccompanyId, id)
                .list()
                .stream()
                .map(AccompanyMember::getUserId)
                .distinct()
                .map(userId -> {
                    User userDto = authService.info(userId.intValue());
                    return UserDTO.builder()
                            .id(userDto.getId())
                            .username(userDto.getUsername())
                            .avatar(userDto.getAvatar())
                            .uid(userDto.getUid())
                            .email(userDto.getEmail())
                            .build();
                })
                .collect(Collectors.toList()));
        response.setUser(list);
        return Result.ok(response);
    }

    @Override
    public Result<List<AccompanyAuditResponse>> queryAccompanyAuditList(Long id) {
        Accompany accompany = getById(id);
        if (accompany == null) {
            return Result.fail("结伴不存在");
        }
        List<AccompanyAuditResponse> list = new ArrayList();
        list.addAll(accompanyMemberService.lambdaQuery()
                .eq(AccompanyMember::getAccompanyId, id)
                .list()
                .stream()
                .filter(accompanyMember -> accompanyMember.getUserId() != StpUtil.getLoginIdAsLong())
                .map(accompanyMember -> {
                    User user = authService.info(accompanyMember.getUserId().intValue());
                    return AccompanyAuditResponse.builder()
                            .id(accompanyMember.getId())
                            .status(accompanyMember.getStatus())
                            .createdTime(accompanyMember.getCreatedTime())
                            .user(UserDTO.builder()
                                    .id(user.getId())
                                    .username(user.getUsername())
                                    .avatar(user.getAvatar())
                                    .uid(user.getUid())
                                    .email(user.getEmail())
                                    .build())
                            .build();
                }).collect(Collectors.toList()));

        return Result.ok(list);

    }
}




